﻿using SuperX.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Ports;
using System.IO;
using System.Text;
using System.Threading;
using SuperX.DataService;
using SuperX.DataService.Abstract;
using SuperX.Common.Abstract;
using HslCommunication.Core.Net;
using HslCommunication.Serial;
using SuperX.DataService.Helper;
using HslCommunication.Core;
using HslCommunication.ModBus;
using SuperX.Common.Log;

namespace SuperX.ModbusDriver
{
    [Description("Modbus RTU协议")]
    public sealed class ModbusRTUReader : ModbusBase, ISerial
    {
        private new string _port = "COM1";

        [Category("串口设置"), Description("串口号")]
        public string PortName
        {
            get { return _port; }
            set { _port = value; }
        }

        public override bool IsClosed
        {
            get
            {
                return PlcReadWrite == null || !client.IsOpen();
            }
        }

        private int _baudRate = 9600;

        [Category("串口设置"), Description("波特率")]
        public int BaudRate
        {
            get { return _baudRate; }
            set { _baudRate = value; }
        }

        private int _dataBits = 8;

        [Category("串口设置"), Description("数据位")]
        public int DataBits
        {
            get { return _dataBits; }
            set { _dataBits = value; }
        }

        private StopBits _stopBits = StopBits.One;

        [Category("串口设置"), Description("停止位")]
        public StopBits StopBits
        {
            get { return _stopBits; }
            set { _stopBits = value; }
        }

        private Parity _parity = Parity.None;

        [Category("串口设置"), Description("奇偶校验")]
        public Parity Parity
        {
            get { return _parity; }
            set { _parity = value; }
        }

        private ModbusRtu client = new ModbusRtu();
        public override IByteTransform ByteTransform { get => client.ByteTransform; }

        public override IReadWriteNet ReadWriteNet { get => client; }

        public ModbusRTUReader() : base()
        {
        }

        public ModbusRTUReader(IDataServer server, string name, string nodeName) : base(server, name, nodeName)
        {
        }

        public override bool Connect()
        {
            if (string.IsNullOrEmpty(PortName)) return false;
            if (PlcReadWrite != null)
            {
                try
                {
                    client.Close();
                    client.Dispose();
                }
                catch (Exception err)
                {
                    Logger.Exception(err);
                }
            }
            client.DataFormat = DataFormat;
            client.SerialPortInni(PortName, BaudRate, DataBits, StopBits, Parity);
            PlcReadWrite = client;
            var result = client.Open();
            return _connected = result.IsSuccess;
        }

        public override void Dispose()
        {
            client?.Close();
            client?.Dispose();
            client = null;
            base.Dispose();
        }

        public override Dictionary<string, string> GetRegester()
        {
            return new Dictionary<string, string>()
            {
                { "x=1;","x=1;"},{ "x=2;","x=2;"},{ "x=3;","x=3;"},{ "x=4;","x=4;"}
            };
        }

        public override DeviceAddress GetDeviceAddress(TagConfig meta)
        {
            var address = meta.Address;
            DeviceAddress dv = DeviceAddress.Empty;
            dv.Addr = address;
            dv.VarType = meta.DataType;
            try
            {
                if (string.IsNullOrEmpty(meta.Regester) || string.IsNullOrEmpty(meta.No))
                    return dv;
                address = meta.No;
                switch (meta.Regester)
                {
                    case "x=1;":
                        {
                            dv.DBNumber = Modbus.fctReadCoil;
                            int st;
                            int.TryParse(address, out st);
                            //dv.Start = (st / 16) * 16;//???????????????????
                            dv.Bit = (byte)(st % 16);
                            st /= 16;
                            dv.Start = st;
                            dv.Bit--;
                            dv.GatherType = GatherType.Digital;
                        }
                        break;

                    case "x=2;":
                        {
                            dv.DBNumber = Modbus.fctReadDiscreteInputs;
                            int st;
                            int.TryParse(address, out st);
                            //dv.Start = (st / 16) * 16;//???????????????????
                            dv.Bit = (byte)(st % 16);
                            st /= 16;
                            dv.Start = st;
                            dv.Bit--;
                            dv.GatherType = GatherType.Digital;
                        }
                        break;

                    case "x=4;":
                        {
                            int index = address.IndexOf('.');
                            dv.DBNumber = Modbus.fctReadHoldingRegister;
                            if (index > 0)
                            {
                                dv.Start = int.Parse(address.Substring(index - 1));
                                dv.Bit = byte.Parse(address.Substring(index + 1));
                                dv.GatherType = GatherType.Digital;
                            }
                            else
                            {
                                dv.Start = int.Parse(address);
                                dv.GatherType = GatherType.Analogue;
                            }
                            dv.ByteOrder = ByteOrder.Network;
                        }
                        break;

                    case "x=3;":
                        {
                            int index = address.IndexOf('.');
                            dv.DBNumber = Modbus.fctReadInputRegister;
                            if (index > 0)
                            {
                                dv.Start = int.Parse(address.Substring(index - 1));
                                dv.Bit = byte.Parse(address.Substring(index + 1));
                            }
                            else
                            {
                                dv.Start = int.Parse(address);
                                dv.GatherType = GatherType.Analogue;
                            }
                            dv.ByteOrder = ByteOrder.Network;
                        }

                        break;
                }
            }
            catch (Exception)
            {
                Logger.Warn($"{address}地址格式有误！");
            }
            return dv;
        }
    }
}